﻿using SharpDepend.WinRT.Classes;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using System;

namespace SharpDepend.WinRT
{
    /// <summary>
    /// Reference: https://msdn.microsoft.com/en-us/library/windows/apps/jj714087(v=vs.105).aspx
    /// </summary>
    internal class FileManager : IFileManagerManager
    {
        string[] SpecialSplit = new string[] { ":/" };

        IAsyncOperation<StorageFile> CreateSpecial(string path)
        {
            IAsyncOperation<StorageFile> item;

            if (path.StartsWith(SpecialDrives.DocumentMusic))
            {
                string path2 = path.Split(SpecialSplit, System.StringSplitOptions.None)[1].Replace('/', '\\');
                item = KnownFolders.MusicLibrary.CreateFileAsync(path2);
            }
            else
            {
                string fixedPath = FixPath(path);

                // Create the local folder.
                item = ApplicationData.Current.LocalFolder.CreateFileAsync(fixedPath);
            }

            return item;
        }

        Task<Stream> OpenSpecialFile(string path)
        {
            Task<Stream> item;

            if (path.StartsWith(SpecialDrives.DocumentMusic))
            {
                item = KnownFolders.MusicLibrary.OpenStreamForReadAsync(path.Split(SpecialSplit, System.StringSplitOptions.None)[1]);
            }
            else
            {
                return null;
            }

            return item;
        }

        StorageFolder GetSpecialFolder(ref string path)
        {
            if (path.StartsWith(SpecialDrives.DocumentMusic))
            {
                path = path.Split(SpecialSplit, System.StringSplitOptions.None)[1];

                if (path.Length > 0)
                {
                    var folder = KnownFolders.MusicLibrary.GetFolderAsync(path);

                    Helper.WaitToComplete(folder);

                    return folder.GetResults();
                }

                return KnownFolders.MusicLibrary;
            }
            else
            {
                // Create the local folder.
                return null;
            }
        }

        StorageFile GetSpecialFile(ref string path)
        {
            if (path.StartsWith(SpecialDrives.DocumentMusic))
            {
                path = path.Split(SpecialSplit, System.StringSplitOptions.None)[1];

                if (path.Length > 0)
                {
                    var file = KnownFolders.MusicLibrary.GetFileAsync(path.Replace('/', '\\'));

                    Helper.WaitToComplete(file);

                    return file.GetResults();
                }
            }

            // Create the local folder.
            return null;
        }

        IAsyncOperation<StorageFolder> CreateSpecialFolder(string path)
        {
            IAsyncOperation<StorageFolder> item;

            if (path.StartsWith(SpecialDrives.DocumentMusic))
            {
                item = KnownFolders.MusicLibrary.CreateFolderAsync(path.Split(SpecialSplit, System.StringSplitOptions.None)[1]);
            }
            else if (path.StartsWith("Picture:"))
            {
                item = KnownFolders.PicturesLibrary.CreateFolderAsync(path.Split(SpecialSplit, System.StringSplitOptions.None)[1]);
            }
            else if (path.StartsWith("Video:"))
            {
                item = KnownFolders.VideosLibrary.CreateFolderAsync(path.Split(SpecialSplit, System.StringSplitOptions.None)[1]);
            }
            else
            {
                string fixedPath = FixPath(path);

                // Create the local folder.
                item = ApplicationData.Current.LocalFolder.CreateFolderAsync(fixedPath);
            }

            return item;
        }

        public bool PathExist(string path, bool directory)
        {
            try
            {
                string checkSPecial = path.Replace("//", "/");
                IStorageItem special = null;

                if (directory)
                {
                    special = GetSpecialFolder(ref checkSPecial);
                }
                else
                {
                    special = GetSpecialFile(ref checkSPecial);

                    if (special == null &&checkSPecial.Length == 0)
                    {
                        return false;
                    }
                }

                if (special != null)
                {
                    if (checkSPecial.Length == 0)
                    {
                        // Then it is root folder for music.
                        return true;
                    }

                    var specialFile = KnownFolders.MusicLibrary.GetItemAsync(checkSPecial.Replace('/', '\\'));
                    Helper.WaitToComplete(specialFile);
                    IStorageItem specialResult = specialFile.GetResults();

                    if (specialFile.Status != AsyncStatus.Error && specialResult != null)
                    {
                        if (directory)
                        {
                            bool isFolder = specialResult.Attributes == (Windows.Storage.FileAttributes)(specialResult.Attributes | Windows.Storage.FileAttributes.Directory);
                            return isFolder;
                        }
                        else
                        {
                            bool isFile = specialResult.Attributes == (Windows.Storage.FileAttributes)(specialResult.Attributes | Windows.Storage.FileAttributes.Archive);
                            return isFile;
                        }
                    }
                    else
                    {
                        // The file doesn't exist.
                        return false;
                    }
                }


                string iPath = FixPath(path);

                if (iPath.Equals("\\"))
                {
                    return true;
                }

                var folder = ApplicationData.Current.LocalFolder;
                //var folder = GetSpecialFolder(ref iPath);
                
                IAsyncOperation<IStorageItem> file = null;

                file = folder.TryGetItemAsync(iPath);

                Helper.WaitToComplete(file);

                IStorageItem result = file.GetResults();
                if (file.Status != AsyncStatus.Error && result != null)
                {
                    if (directory)
                    {
                        bool isFolder = result.Attributes == (Windows.Storage.FileAttributes)(result.Attributes | Windows.Storage.FileAttributes.Directory);
                        return isFolder;
                    }
                    else
                    {
                        bool isFile = result.Attributes == (Windows.Storage.FileAttributes)(result.Attributes | Windows.Storage.FileAttributes.Archive);
                        return isFile;
                    }
                }
                else
                {
                    // The file doesn't exist.
                    return false;
                }
            }
            catch (System.Exception)
            {
                return false;
            }
        }

        public void CreateFolder(string path)
        {
            // Create the local folder.
            IAsyncOperation<StorageFolder> item = CreateSpecialFolder(path);

            Helper.WaitToComplete(item);
        }

        public Stream CreateFile(string path)
        {
            // Remove first.
            if (PathExist(path, false))
            {
                DeleteFile(path);
            }
            
            // Create the local folder.
            IAsyncOperation<StorageFile> item = CreateSpecial(path);

            Helper.WaitToComplete(item);

            IAsyncOperation<IRandomAccessStream> streamInfo = item.GetResults().OpenAsync(FileAccessMode.ReadWrite);

            Helper.WaitToComplete(streamInfo);

            return streamInfo.GetResults().AsStream();
        }

        public Stream OpenFile(string path)
        {
            string checkSPecial = path;
            var special = OpenSpecialFile(checkSPecial);
            if (special != null)
            {
                Helper.WaitToComplete(special);

                return special.Result;
            }

            string fullPath = FixFullPath(path);

            IAsyncOperation<StorageFile> file = StorageFile.GetFileFromPathAsync(fullPath);

            Helper.WaitToComplete(file);

            IAsyncOperation<IRandomAccessStream> streamInfo = file.GetResults().OpenAsync(FileAccessMode.ReadWrite);

            Helper.WaitToComplete(streamInfo);

            return streamInfo.GetResults().AsStream();
        }

        private static string FixFullPath(string path)
        {
            if (path.Contains("//"))
            {
                path = path.Replace("//", "/");
            }

            if (path.Contains("\\\\"))
            {
                path = path.Replace("\\\\", "\\");
            }

            string fullPath = ApplicationData.Current.LocalFolder.Path + FixPath(path);
            return fullPath;
        }

        private static string FixPath(string path)
        {
            path = path.Replace('/', '\\');
            if (path.StartsWith(".\\"))
            {
                return path.Substring(1);
            }

            if (path.EndsWith("\\"))
            {
                path = path.Substring(0, path.Length - 1);
            }

            return path;
        }

        public string[] ListFiles(string folderPath)
        {
            string checkSPecial = folderPath;
            var special = GetSpecialFolder(ref checkSPecial);

            if (special != null)
            {
                IAsyncOperation<IReadOnlyList<StorageFile>> songs = special.GetFilesAsync();

                Helper.WaitToComplete(songs);

                IReadOnlyList<StorageFile> completedListSongs = songs.GetResults();

                string[] array2 = new string[completedListSongs.Count];

                int i2 = -1;
                foreach (var item in completedListSongs)
                {
                    string p = folderPath + "/" + item.Name;
                    
                    array2[++i2] = p;
                }
                
                return array2;
            }

            string fullPath = FixFullPath(folderPath);

            IAsyncOperation<StorageFolder> folder = StorageFolder.GetFolderFromPathAsync(fullPath);

            Helper.WaitToComplete(folder);

            IAsyncOperation<IReadOnlyList<StorageFile>> list = folder.GetResults().GetFilesAsync();

            Helper.WaitToComplete(list);

            IReadOnlyList<StorageFile> completedList = list.GetResults();

            string[] array = new string[completedList.Count];

            string fullP = FixFullPath("./");

            int i = -1;
            foreach (var item in completedList)
            {
                string p = item.Path;

                p = "./" + p.Substring(fullP.Length);

                array[++i] = p;
            }

            return array;
        }

        public string[] ListFolders(string folderPath)
        {
            string checkSPecial = folderPath;
            var special = GetSpecialFolder(ref checkSPecial);

            if (special != null)
            {
                var foldersTask = special.GetFoldersAsync();

                Helper.WaitToComplete(foldersTask);

                var specialFolders = foldersTask.GetResults();

                string[] sfolders = new string[specialFolders.Count];
                for (int i = 0; i < sfolders.Length; i++)
                {
                    string path = specialFolders[i].FolderRelativeId;
                    path = path.Substring(path.IndexOf('\\') + 1);

                    sfolders[i] = SpecialDrives.DocumentMusic + path;
                }

                return sfolders;
            }

            string fullPath = FixFullPath(folderPath);

            IAsyncOperation<StorageFolder> folder = StorageFolder.GetFolderFromPathAsync(fullPath);

            Helper.WaitToComplete(folder);

            IAsyncOperation<IReadOnlyList<StorageFolder>> list = folder.GetResults().GetFoldersAsync();

            Helper.WaitToComplete(list);

            IReadOnlyList<StorageFolder> completedList = list.GetResults();

            string[] array = GetFilesAsArray(completedList);

            return array;
        }

        private static string[] GetFilesAsArray<TStorageItem>(IReadOnlyList<TStorageItem> completedList) where TStorageItem : IStorageItem
        {
            string[] array = new string[completedList.Count];

            string fullP = FixFullPath("./");

            int i = -1;
            foreach (var item in completedList)
            {
                string p = item.Path;

                p = "./" + p.Substring(fullP.Length);

                array[++i] = p;
            }

            return array;
        }

        private static string[] GetFoldersAsArray<TStorageItem>(IReadOnlyList<TStorageItem> completedList) where TStorageItem : IStorageItem
        {
            string[] array = new string[completedList.Count];

            string fullP = FixFullPath("./");

            int i = -1;
            foreach (var item in completedList)
            {
                string p = item.Path + "\\";

                p = "./" + p.Substring(fullP.Length);

                array[++i] = p;
            }

            return array;
        }

        public void CopyFile(Stream source, string destinationPath)
        {
            using (var streamDestination = CreateFile(destinationPath))
            {
                const int SIZE = 1024;
                byte[] buffer = new byte[SIZE];
                int read = SIZE;
                while (read == SIZE)
                {
                    read = source.Read(buffer, 0, SIZE);
                    streamDestination.Write(buffer, 0, read);
                }
            }
        }

        public void MoveFile(string sourcePath, string destinationPath)
        {
            string fullSourcelPath = FixFullPath(sourcePath);
            string fullDestinationPath = FixFullPath(destinationPath);

            // Split destination path and filename.
            fullDestinationPath = fullDestinationPath.Replace('/', '\\');
            string desPath = fullDestinationPath.Substring(0, fullDestinationPath.LastIndexOf('\\'));
            string desFilename = fullDestinationPath.Substring(fullDestinationPath.LastIndexOf('\\'));

            IAsyncOperation<StorageFile> sp = StorageFile.GetFileFromPathAsync(fullSourcelPath);
            IAsyncOperation<StorageFolder> dp = StorageFolder.GetFolderFromPathAsync(fullDestinationPath);

            Helper.WaitToComplete(sp);
            Helper.WaitToComplete(dp);

            var move = sp.GetResults().MoveAsync(dp.GetResults(), desFilename);

            Helper.WaitToComplete(move);
        }

        public void DeleteFile(string filePath)
        {
            if (filePath.StartsWith(SpecialDrives.DocumentMusic))
            {
                string path = filePath.Split(SpecialSplit, System.StringSplitOptions.None)[1];

                if (path.Length > 0)
                {
                    var file = KnownFolders.MusicLibrary.GetFileAsync(path.Replace('/', '\\'));

                    Helper.WaitToComplete(file);

                   var deleteas = file.GetResults().DeleteAsync(StorageDeleteOption.Default);

                    Helper.WaitToComplete(deleteas);

                    return;
                }
            }

            string fullSourcePath = FixFullPath(filePath);

            IAsyncOperation<StorageFile> sp = StorageFile.GetFileFromPathAsync(fullSourcePath);

            Helper.WaitToComplete(sp);

            var delete = sp.GetResults().DeleteAsync();

            Helper.WaitToComplete(delete);
        }

        public void DeleteFolder(string folderPath)
        {
            string fullSourcePath = FixFullPath(folderPath);

            IAsyncOperation<StorageFolder> sp = StorageFolder.GetFolderFromPathAsync(fullSourcePath);

            Helper.WaitToComplete(sp);

            var delete = sp.GetResults().DeleteAsync();

            Helper.WaitToComplete(delete);
        }

        public string[] GetDrives(DriveType driveType)
        {
            return new string[0];
        }
    }
}
